/*  -*- mode: c++; coding: utf-8; c-file-style: "stroustrup"; -*-

    Copyright 2008 Asier Aguirre <asier.aguirre@gmail.com>
    This file is part of Intromit.

    Intromit is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Intromit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Intromit.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef RENDER_OBJ_CAMERA_HH
#define RENDER_OBJ_CAMERA_HH
//! \addtogroup introsight_framework
//@{

// INCLUDES
#include "render_obj.hh"

// STRUCTS
struct action_attraction_str
{
    double position[IS_3D];
    double lookat[IS_3D];
    double vertical[IS_3D];
    double velocity;
    double calculated_position[IS_3D];
    double calculated_angle[IS_SPHERIC];
};

// CLASSES
class render_mng;

class render_obj_camera: public render_obj
{
    // camera parameters
    float fov, zmin, zmax, aspect;
    double focal; // precalculated
    double angle[IS_SPHERIC], angle_goto[IS_SPHERIC], angle_bak[IS_SPHERIC];
    double position[IS_3D], position_goto[IS_3D], position_bak[IS_3D];
    double velo_att[2];
    int update_timer;

    // movement parameters
    double angle_mouse_ratio[IS_SPHERIC];
    double angle_momentum[IS_SPHERIC];
    double movement_velo;
    double movement_inertia;

    // attraction
    action_attraction_str attraction;
    int n_attraction; // 0: nothing to do  >0: to be calculated  -1: calculated, to be updated

    // horizon
    bool horizon;
    int n_horizon_parallels, n_horizon_parpoints;
    int n_horizon_meridians, n_horizon_merpoints;
    float horizon_color[IS_RGBA];
    unsigned horizon_call_list;

    // precalcs
    double prec_c_azim, prec_s_azim, prec_c_elev, prec_s_elev;

    // PRIVATE METHODS
    void ctor();
    void dtor();

    // navigation
    void update_cinematics(render_mng *ctx);
    int update_time();
    void update_angle(double time_diff);
    void update_vector(render_mng *ctx, double time_diff);
    void update_vector_goto(render_mng *ctx);
    void calculate_attraction();
    void update_attraction(double time_diff);
    void reset_attraction();

    // actions
    bool action_dispatcher(render_mng *ctx, unsigned type, unsigned event);
    bool action_navigate(render_mng *ctx, unsigned event);
    bool action_center(render_mng *ctx);
    bool action_attraction(render_mng *ctx);

    // matrix camera operations
    void matrix_angle_update(); // calls matrix_precalc_trig and matrix_get_*_vector
    void matrix_position_update();
    void matrix_precalc_trig();
    void matrix_precalc_trig(double azim, double elev);
    void matrix_get_longitudinal_vector(double *v);
    void matrix_get_traversal_vector(double *v);
    void matrix_get_vertical_vector(double *v);

    // rendering
    void render_horizon();

    // util
    void angle_unwrap_nearest();

public:
    render_obj_camera();
    virtual ~render_obj_camera();

    virtual bool init(render_mng *ctx);
    virtual void render(render_mng *ctx);
    virtual bool event(render_mng *ctx);
    virtual unsigned get_type();           // returns IS_TYPE_*

    void set_camera_parameters(float fov, float zmin, float zmax, float aspect);
    inline double get_focal() {return focal;}

    void goto_position(render_mng *ctx, double pos[IS_3D], double lookat[IS_3D], double vertical[IS_3D]);
};

//@}
#endif

/* Offline metadata attributes:

   @metadata_attrs(
	render_obj_camera
	{
		# members
		fov, zmin, zmax, aspect,
		angle, angle_goto,
		angle_mouse_ratio,
		angle_momentum,
		position, position_goto,
		movement_velo,
		movement_inertia,
		velo_att:
						select
		horizon,
		horizon_color,
		n_horizon_parallels,
		n_horizon_parpoints,
		n_horizon_meridians,
		n_horizon_merpoints:
						select, read_only

		# methods
		init, render,
		set_camera_parameters:
						select
	}
   )
*/
